//
//  main.c
//  LC3Compiler
//
//  Created by Anthony Sierra on 5/31/11.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//
/*
 Function Numbers:
 1 = ADD
 2 = AND
 */


#include <stdio.h>
#include <ctype.h>
#include "ArrayList.h"
/*
 Global Variables-----------------
 */
FILE *fr, *output_file;
int *statements;
ArrayList word_library;

//Functions----------------------
int command(const char *message);
void addFunction();
void andFunction();
void addSyntaxCheck(const char *first, int program_counter);
void andSyntaxCheck(const char *first, int program_counter);
void brSyntaxCheck(char *first, int program_counter);
int checkSymbols(char *word, int program_counter);
int checkDictionary(char *word);
char words[25][20];

int main (int argc, const char * argv[])
{
    //Make integer program counter for counting where we are in the file.
    int origin = 0;
    
    strcpy(words[0], "ADD");
    strcpy(words[1], "AND");
    strcpy(words[2], "BR");
    strcpy(words[3], "JMP");
    strcpy(words[4], "JSR");
    strcpy(words[5], "JSRR");
    strcpy(words[6], "LD");
    strcpy(words[7], "LDI");
    strcpy(words[8], "LDR");
    strcpy(words[9], "LEA");
    strcpy(words[10], "NOT");
    strcpy(words[11], "RET");
    strcpy(words[12], "RTI");
    strcpy(words[13], "ST");
    strcpy(words[14], "STI");
    strcpy(words[15], "STR");
    strcpy(words[16], "TRAP");
    strcpy(words[17], "PUSH");
    strcpy(words[18], "POP");
    strcpy(words[19], "NEG");
    strcpy(words[20], ".ORIG");
    strcpy(words[21], ".FILL");
    strcpy(words[22], ".BLKW");
    strcpy(words[23], ".STRINGZ");
    strcpy(words[24], ".END");
    
    //Library of words in the program.
    initializeArrayList(&word_library);
    /*
    new.name = "Wasup";
    new.line_number = 4;
    addItemToEndOfArrayList(&word_library, new);
    new.name = "Waasdfsup";
    new.line_number = 6;
    addItemToEndOfArrayList(&word_library, new);
    printf("%s", getItem(&word_library, 0).name);
    printf("%s", getItem(&word_library, 1).name);*/
    
    
    //Variable for reading.
    char message[30];
    //Open the file for reading and compiling
    fr = fopen("/Users/anthonysierra/Documents/School/Machine Organization/LC3Compiler/LC3Compiler/TextFile.txt", "rw");
    //Setup the file that we are outputting to.
    output_file = fopen("/Users/anthonysierra/Desktop/FileReading/FileReading/output.txt", "w");
    
    
    //Check to make sure the file that was opened was readable.
    if (fr == NULL) {
        printf("Couldnt open text\n");
        exit(1);
    }
    //Check to make sure the file to output to was created or exists.
    if (output_file == NULL) {
        printf("Couldnt Open or Create Output file\n");
        exit(1);
    }
    
    /*
     Get the Origin of the File
     */
    fscanf(fr, "%30s", message);
    //if there is anything that is not .ORIG then ouput error and poop out.
    if (strcmp(message, ".ORIG") > 0 || strcmp(message, ".ORIG") < 0)
    {
        printf(".ORIG expected but found %s", message);
        exit(1);
    }
    /*
     Get the starting value of the origin.
     */
    fscanf(fr, "%30s", message);
    if (message[0] == 'x')
    {
        char temp[30];
        int length = 0;
        while (message[length] != '\0')
        {
            length++;
        }
        for (int i = 0; i<= length; i++)
        {
            temp[i] = message[i+1];
        }
        //set origin to the passed in number
        origin = atoi(temp);
    }
    else
    {
        //set origin to the passed in number
        origin = atoi(message);
    }
    if (origin < 0x0200 || origin > 0xFE00)
    {
        printf("Expected Valid Hex value instead got %d", origin);
        exit(1);
    }
    
    
    
    
    
    
    
    char stuff[40];
    int program_counter = 0;
    /*
     This would be for the first pass
     */
    while (fgets(stuff, 40, fr) && stuff != EOF) {
        int i = 0;
        char upper_case_string[30];
        while(stuff[i])
        {
            upper_case_string[i] = toupper(stuff[i]);
            i++;
        }
        char *first;
        first = strtok(stuff, " ,;\n");
        while (first != NULL) {
            if (checkDictionary(first))
            {
                //if ADD
                if (!strcmp(first, words[0]))
                {
                    addSyntaxCheck(first, program_counter);
                }//end if
    
                else if (!strcmp(first, words[1])) { //if AND
                    andSyntaxCheck(first, program_counter);
                }
                else if (first[0] == 'B' && first[1] == 'R') { //if BR
                    brSyntaxCheck(first, program_counter);
                }
                else if (!strcmp(first, words[3])) { // If JMP
                    first = strtok(NULL, " ,;");
                    char integer[30];
                    int length = 0;
                    while (first[length+1] != '\0')
                    {
                        integer[length] = first[length+1];
                        length++;
                    }
                    integer[length] = '\0';
                    
                    int number = atoi(integer);
                    if (first[0] != 'R' || number < 0 || number > 7 ) {printf("Expected R0-7 but found %s at Line Number: %d\n", first, program_counter);}
                }
            }
            else {
                Symbol *label = (Symbol*)malloc(sizeof(Symbol));
                label->name = (char*)malloc(30*sizeof(char));
                strcpy(label->name, first);
                label->line_number = program_counter;
                //printf("%d\n", &label->name);
                if (checkSymbols(label->name, program_counter)) {
                    printf("Already specified name %s found on line %d", first, program_counter);
                } else {
                    addItemToEndOfArrayList(&word_library, label);
                }
            }
            first = strtok(NULL, " ,;\n");
        }//end while
        program_counter++;
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    //This Code example would be for pass 2
    /*
     While file is not empty
     Program Counter Increase at End
     */
   /* switch (command("ADD"))
    {
        case 1:
            addFunction();
            break;
        case 2:
            andFunction();
            break;
    }*/
    return 0;
}
/**
 Goes through array of Symbols made by user and returns a one if
 the label has been previously made. Else returns 0;
 */
int checkSymbols(char *word, int program_counter) {
    int result = 0;
    for (int i = 0; i < getSize(&word_library); i++) {
        if (strcmp(getItem(&word_library, i)->name, word) == 0) {
            result = 1;
            break;
        }
    }
    return result;
}
int checkDictionary(char *word)
{
    int result = 0;
    for (int i = 0; i < 25; i++) {
        if(!strcmp(word, words[i]))
           {
               result = 1;
               break;
           }
        if (word[0] == 'B' && word[1] == 'R') {
            result = 1;
            break; 
        }
    }
    return result;
}
void setup()
{
    
}
/*
 This checks to see what command was issued.
 */
int command(const char *message)
{
    int ret_val = 0;
    if (!strcmp(message, "ADD") || !strcmp(message, "ADD,"))
    {
        ret_val = 1;
    }
    else if (!strcmp(message, "AND") || !strcmp(message, "AND,"))
    {
        ret_val = 2;
    }
    return ret_val;
}
void addSyntaxCheck(const char *first, int program_counter)
{
    first = strtok(NULL, " ,;");
    char integer[30];
    int length = 0;
    while (first[length+1] != '\0')
    {
        integer[length] = first[length+1];
        length++;
    }
    integer[length] = '\0';
    
    int number = atoi(integer);
    
    if (first[0] != 'R' || number < 0 || number > 7 ) {printf("Expected R0-7 but found %s at Line Number: %d\n", first, program_counter);}
    first = strtok(NULL, " ,;");
    length = 0;
    while (first[length+1] != '\0')
    {
        integer[length] = first[length+1];
        length++;
    }
    integer[length] = '\0';
    number = atoi(integer);
    
    if (first[0] != 'R'|| number < 0 || number > 7 ) {printf("Expected R0-7 but found %s at Line Number: %d\n", first, program_counter);}
    first = strtok(NULL, " ,;");
    length = 0;
    while (first[length+1] != '\0')
    {
        integer[length] = first[length+1];
        length++;
    }
    integer[length] = '\0';
    number = atoi(integer);
    
    if (first[0] == 'R')
    {
        if (number < 0 || number > 7 ) {printf("Expected R0-7 or # but found %s at Line Number: %d\n", first, program_counter);}
    }
    else if (first[0] == '#')
    {
        char *integer = strtok(first, "#");
        int number = atoi(integer);
        if (number < -16 || number > 15) { printf("%d cannot be represented as a signed number in 5 bits  at Line Number: %d", number, program_counter);}//end #
    }//end else if
}
void andSyntaxCheck(const char *first, int program_counter) {
    first = strtok(NULL, " ,;");
    char integer[30];
    int length = 0;
    while (first[length+1] != '\0')
    {
        integer[length] = first[length+1];
        length++;
    }
    integer[length] = '\0';
    
    int number = atoi(integer);
    
    if (first[0] != 'R' || number < 0 || number > 7 ) {printf("Expected R0-7 but found %s at Line Number: %d\n", first, program_counter);}
    first = strtok(NULL, " ,;");
    length = 0;
    while (first[length+1] != '\0')
    {
        integer[length] = first[length+1];
        length++;
    }
    integer[length] = '\0';
    number = atoi(integer);
    
    if (first[0] != 'R'|| number < 0 || number > 7 ) {printf("Expected R0-7 but found %s at Line Number: %d\n", first, program_counter);}
    first = strtok(NULL, " ,;");
    length = 0;
    while (first[length+1] != '\0')
    {
        integer[length] = first[length+1];
        length++;
    }
    integer[length] = '\0';
    number = atoi(integer);
    
    if (first[0] == 'R')
    {
        if (number < 0 || number > 7 ) {printf("Expected R0-7 or # but found %s at Line Number: %d\n", first, program_counter);}
    }
    else if (first[0] == '#')
    {
        char *integer = strtok(first, "#");
        int number = atoi(integer);
        if (number < -16 || number > 15) { printf("%d cannot be represented as a signed number in 5 bits  at Line Number: %d", number, program_counter);}//end #
    }//end else if
}
void brSyntaxCheck(char *first, int program_counter)
{
    char thing[4];
    int i = 0;
    while (first[i+2])
    {
        thing[i] = first[i+2];
        i++;
    }
    thing[i] = '\0';
    if (thing[0] == 'n')
    {
        if (thing[1] == 'z') {
            if (thing[2] == 'p') {
                if (thing[3] != '\0') {
                    printf("Error BRnzp or varient expected else got %s", first);
                }
            }
            else if (thing[2] != '\0') {
                printf("Error BRnzp or varient expected else got %s", first);
            }
        }
        else if(thing[1] == 'p') {
            if (thing[2] != '\0') {
                printf("Error BRnzp or varient expected else got %s", first);
            }
        }
    }
    else if (thing[0] == 'z') {
        if (thing[1] == 'p') {
            if (thing[2] != '\0') {
                printf("Error BRnzp or varient expected else got %s", first);
            }
        }
        else if (thing[1] != '\0') {
            printf("Error BRnzp or varient expected else got %s", first);
        }
    }
    else if (thing[0] == 'p') {
        if (thing[1] != '\0') {
            printf("Error BRnzp or varient expected else got %s", first);
        }
    }
    first = strtok(NULL, " ,;");
    //get rid of \n at end if there is one.
    int len = (int)strlen(first);
    if (first[len-1] == '\n') {
        first[len-1] = '\0';
    }
    if (!checkSymbols(first, program_counter)) {
        printf("Unspecified Symbol %s\n", first);
    }
}

void fillSyntaxCheck(const char *first, int program_counter) {
	first = strtok(NULL, " ");
	char string[30];
	strcpy(string, first);
	if((string[0] >= '0' && string[0] <= '9') || string[0] == '#' ||  string[0] == '-') {//check if it starts with a number
		if(string[1] != '\0' && (string[1] == 'x' || string[1] == 'X')) {// hexidecimal

		} else {
			int number = atoi(string);

			if(number > 65535 || number < 32768) {
				printf("%d cannot be represented as an unsigned number in 16 bits on line %d",
																		number, program_counter);
			}
		}

	} else {
		first = strtok(NULL, " ");
		strcpy(string, first);

		if(string[0] != ';') {
			printf("Unrecognized and invalid opcode on line %d", program_counter);
		}
	}
	program_counter++;
}
/*
 This executes the addition command in the lc3
 */
void addFunction()
{
    
}
/*
 This executes the and command in the lc3
 */
void andFunction()
{
    
}
